home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / initsnb.zoo / init / sh / mkinit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-09  |  11.1 KB  |  551 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
  40.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. static char sccsid[] = "@(#)mkinit.c    5.3 (Berkeley) 3/13/91";
  45. #endif /* not lint */
  46.  
  47. /*
  48.  * This program scans all the source files for code to handle various
  49.  * special events and combines this code into one file.  This (allegedly)
  50.  * improves the structure of the program since there is no need for
  51.  * anyone outside of a module to know that that module performs special
  52.  * operations on particular events.  The command is executed iff init.c
  53.  * is actually changed.
  54.  *
  55.  * Usage:  mkinit command sourcefile...
  56.  */
  57.  
  58.  
  59. #include <ctype.h>
  60. #include <stdio.h>
  61. #include <fcntl.h>
  62.  
  63. #ifdef __STDC__
  64. #  define __P(x) x
  65. #else
  66. #  define __P(x)
  67. #endif
  68.  
  69. /*
  70.  * OUTFILE is the name of the output file.  Output is initially written
  71.  * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and
  72.  * OUTFILE are different.
  73.  */
  74.  
  75. #define OUTFILE "init.c"
  76. #define OUTTEMP "init.c.new"
  77. #define OUTOBJ "init.o"
  78.  
  79.  
  80. /*
  81.  * A text structure is basicly just a string that grows as more characters
  82.  * are added onto the end of it.  It is implemented as a linked list of
  83.  * blocks of characters.  The routines addstr and addchar append a string
  84.  * or a single character, respectively, to a text structure.  Writetext
  85.  * writes the contents of a text structure to a file.
  86.  */
  87.  
  88. #define BLOCKSIZE 512
  89.  
  90. struct text {
  91.     char *nextc;
  92.     int nleft;
  93.     struct block *start;
  94.     struct block *last;
  95. };      
  96.  
  97. struct block {
  98.     struct block *next;
  99.     char text[BLOCKSIZE];
  100. };
  101.  
  102.  
  103. /*
  104.  * There is one event structure for each event that mkinit handles.
  105.  */
  106.  
  107. struct event {
  108.     char *name;        /* name of event (e.g. INIT) */
  109.     char *routine;        /* name of routine called on event */
  110.     char *comment;        /* comment describing routine */
  111.     struct text code;        /* code for handling event */
  112. };
  113.  
  114.  
  115. char writer[] = "\
  116. /*\n\
  117.  * This file was generated by the mkinit program.\n\
  118.  */\n\
  119. \n";
  120.  
  121. char init[] = "\
  122. /*\n\
  123.  * Initialization code.\n\
  124.  */\n";
  125.  
  126. char reset[] = "\
  127. /*\n\
  128.  * This routine is called when an error or an interrupt occurs in an\n\
  129.  * interactive shell and control is returned to the main command loop.\n\
  130.  */\n";
  131.  
  132. char shellproc[] = "\
  133. /*\n\
  134.  * This routine is called to initialize the shell to run a shell procedure.\n\
  135.  */\n";
  136.  
  137.  
  138. struct event event[] = {
  139.     {"INIT", "init", init},
  140.     {"RESET", "reset", reset},
  141.     {"SHELLPROC", "initshellproc", shellproc},
  142.     {NULL, NULL}
  143. };
  144.  
  145.  
  146. char *curfile;                /* current file */
  147. int linno;                /* current line */
  148. char *header_files[200];        /* list of header files */
  149. struct text defines;            /* #define statements */
  150. struct text decls;            /* declarations */
  151. int amiddecls;                /* for formatting */
  152.  
  153.  
  154. void readfile(), doevent(), doinclude(), dodecl(), output();
  155. void addstr(), addchar(), writetext();
  156.  
  157. #define equal(s1, s2)    (strcmp(s1, s2) == 0)
  158.  
  159. FILE *ckfopen();
  160. char *savestr();
  161. void *ckmalloc __P((int));
  162. void error();
  163.  
  164. main(argc, argv)
  165.     char **argv;
  166.     {
  167.     char **ap;
  168.     int fd;
  169.     char c;
  170.  
  171.     if (argc < 2)
  172.         error("Usage:  mkinit command file...");
  173.     header_files[0] = "\"shell.h\"";
  174.     header_files[1] = "\"mystring.h\"";
  175.     for (ap = argv + 2 ; *ap ; ap++)
  176.         readfile(*ap);
  177.     output();
  178.     if (file_changed()) {
  179.         unlink(OUTFILE);
  180.         link(OUTTEMP, OUTFILE);
  181.         unlink(OUTTEMP);
  182.     } else {
  183.         unlink(OUTTEMP);
  184.         if (touch(OUTOBJ))
  185.             exit(0);        /* no compilation necessary */
  186.     }
  187.     printf("%s\n", argv[1]);
  188.     execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
  189.     error("Can't exec shell");
  190. }
  191.  
  192.  
  193. /*
  194.  * Parse an input file.
  195.  */
  196.  
  197. void
  198. readfile(fname)
  199.     char *fname;
  200.     {
  201.     FILE *fp;
  202.     char line[1024];
  203.     struct event *ep;
  204.  
  205.     fp = ckfopen(fname, "r");
  206.     curfile = fname;
  207.     linno = 0;
  208.     amiddecls = 0;
  209.     while (fgets(line, sizeof line, fp) != NULL) {
  210.         linno++;
  211.         for (ep = event ; ep->name ; ep++) {
  212.             if (line[0] == ep->name[0] && match(ep->name, line)) {
  213.                 doevent(ep, fp, fname);
  214.                 break;
  215.             }
  216.         }
  217.         if (line[0] == 'I' && match("INCLUDE", line))
  218.             doinclude(line);
  219.         if (line[0] == 'M' && match("MKINIT", line))
  220.             dodecl(line, fp);
  221.         if (line[0] == '#' && gooddefine(line))
  222.             addstr(line, &defines);
  223.     }
  224.     fclose(fp);
  225. }
  226.  
  227.  
  228. int
  229. match(name, line)
  230.     char *name;
  231.     char *line;
  232.     {
  233.     register char *p, *q;
  234.  
  235.     p = name, q = line;
  236.     while (*p) {
  237.         if (*p++ != *q++)
  238.             return 0;
  239.     }
  240.     if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
  241.         return 0;
  242.     return 1;
  243. }
  244.  
  245.  
  246. int
  247. gooddefine(line)
  248.     char *line;
  249.     {
  250.     register char *p;
  251.  
  252.     if (! match("#define", line))
  253.         return 0;            /* not a define */
  254.     p = line + 7;
  255.     while (*p == ' ' || *p == '\t')
  256.         p++;
  257.     while (*p != ' ' && *p != '\t') {
  258.         if (*p == '(')
  259.             return 0;        /* macro definition */
  260.         p++;
  261.     }
  262.     while (*p != '\n' && *p != '\0')
  263.         p++;
  264.     if (p[-1] == '\\')
  265.         return 0;            /* multi-line definition */
  266.     return 1;
  267. }
  268.  
  269.  
  270. void
  271. doevent(ep, fp, fname)
  272.     register struct event *ep;
  273.     FILE *fp;
  274.     char *fname;
  275.     {
  276.     char line[1024];
  277.     int indent;
  278.     char *p;
  279.  
  280.     sprintf(line, "\n      /* from %s: */\n", fname);
  281.     addstr(line, &ep->code);
  282.     addstr("      {\n", &ep->code);
  283.     for (;;) {
  284.         linno++;
  285.         if (fgets(line, sizeof line, fp) == NULL)
  286.             error("Unexpected EOF");
  287.         if (equal(line, "}\n"))
  288.             break;
  289.         indent = 6;
  290.         for (p = line ; *p == '\t' ; p++)
  291.             indent += 8;
  292.         for ( ; *p == ' ' ; p++)
  293.             indent++;
  294.         if (*p == '\n' || *p == '#')
  295.             indent = 0;
  296.         while (indent >= 8) {
  297.             addchar('\t', &ep->code);
  298.             indent -= 8;
  299.         }
  300.         while (indent > 0) {
  301.             addchar(' ', &ep->code);
  302.             indent--;
  303.         }
  304.         addstr(p, &ep->code);
  305.     }
  306.     addstr("      }\n", &ep->code);
  307. }
  308.  
  309.  
  310. void
  311. doinclude(line)
  312.     char *line;
  313.     {
  314.     register char *p;
  315.     char *name;
  316.     register char **pp;
  317.  
  318.     for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
  319.     if (*p == '\0')
  320.         error("Expecting '\"' or '<'");
  321.     name = p;
  322.     while (*p != ' ' && *p != '\t' && *p != '\n')
  323.         p++;
  324.     if (p[-1] != '"' && p[-1] != '>')
  325.         error("Missing terminator");
  326.     *p = '\0';
  327.  
  328.     /* name now contains the name of the include file */
  329.     for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
  330.     if (*pp == NULL)
  331.         *pp = savestr(name);
  332. }
  333.  
  334.  
  335. void
  336. dodecl(line1, fp)
  337.     char *line1;
  338.     FILE *fp;
  339.     {
  340.     char line[1024];
  341.     register char *p, *q;
  342.  
  343.     if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
  344.         addchar('\n', &decls);
  345.         do {
  346.             linno++;
  347.             if (fgets(line, sizeof line, fp) == NULL)
  348.                 error("Unterminated structure declaration");
  349.             addstr(line, &decls);
  350.         } while (line[0] != '}');
  351.         amiddecls = 0;
  352.     } else {
  353.         if (! amiddecls)
  354.             addchar('\n', &decls);
  355.         q = NULL;
  356.         for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++);
  357.         if (*p == '=') {        /* eliminate initialization */
  358.             for (q = p ; *q && *q != ';' ; q++);
  359.             if (*q == '\0')
  360.                 q = NULL;
  361.             else {
  362.                 while (p[-1] == ' ')
  363.                     p--;
  364.                 *p = '\0';
  365.             }
  366.         }
  367.         addstr("extern", &decls);
  368.         addstr(line1 + 6, &decls);
  369.         if (q != NULL)
  370.             addstr(q, &decls);
  371.         amiddecls = 1;
  372.     }
  373. }
  374.  
  375.  
  376.  
  377. /*
  378.  * Write the output to the file OUTTEMP.
  379.  */
  380.  
  381. void
  382. output() {
  383.     FILE *fp;
  384.     char **pp;
  385.     struct event *ep;
  386.  
  387.     fp = ckfopen(OUTTEMP, "w");
  388.     fputs(writer, fp);
  389.     for (pp = header_files ; *pp ; pp++)
  390.         fprintf(fp, "#include %s\n", *pp);
  391.     fputs("\n\n\n", fp);
  392.     writetext(&defines, fp);
  393.     fputs("\n\n", fp);
  394.     writetext(&decls, fp);
  395.     for (ep = event ; ep->name ; ep++) {
  396.         fputs("\n\n\n", fp);
  397.         fputs(ep->comment, fp);
  398.         fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
  399.         writetext(&ep->code, fp);
  400.         fprintf(fp, "}\n");
  401.     }
  402.     fclose(fp);
  403. }
  404.  
  405.  
  406. /*
  407.  * Return true if the new output file is different from the old one.
  408.  */
  409.  
  410. int
  411. file_changed() {
  412.     register FILE *f1, *f2;
  413.     register int c;
  414.  
  415.     if ((f1 = fopen(OUTFILE, "r")) == NULL
  416.      || (f2 = fopen(OUTTEMP, "r")) == NULL)
  417.         return 1;
  418.     while ((c = getc(f1)) == getc(f2)) {
  419.         if (c == EOF)
  420.             return 0;
  421.     }
  422.     return 1;
  423. }
  424.  
  425.  
  426. /*
  427.  * Touch a file.  Returns 0 on failure, 1 on success.
  428.  */
  429.  
  430. int
  431. touch(file)
  432.     char *file;
  433.     {
  434.     int fd;
  435.     char c;
  436.  
  437.     if ((fd = open(file, O_RDWR)) < 0)
  438.         return 0;
  439.     if (read(fd, &c, 1) != 1) {
  440.         close(fd);
  441.         return 0;
  442.     }
  443.     lseek(fd, 0L, 0);
  444.     write(fd, &c, 1);
  445.     close(fd);
  446.     return 1;
  447. }
  448.  
  449.  
  450.  
  451. /*
  452.  * A text structure is simply a block of text that is kept in memory.
  453.  * Addstr appends a string to the text struct, and addchar appends a single
  454.  * character.
  455.  */
  456.  
  457. void
  458. addstr(s, text)
  459.     register char *s;
  460.     register struct text *text;
  461.     {
  462.     while (*s) {
  463.         if (--text->nleft < 0)
  464.             addchar(*s++, text);
  465.         else
  466.             *text->nextc++ = *s++;
  467.     }
  468. }
  469.  
  470.  
  471. void
  472. addchar(c, text)
  473.     register struct text *text;
  474.     {
  475.     struct block *bp;
  476.  
  477.     if (--text->nleft < 0) {
  478.         bp = ckmalloc(sizeof *bp);
  479.         if (text->start == NULL)
  480.             text->start = bp;
  481.         else
  482.             text->last->next = bp;
  483.         text->last = bp;
  484.         text->nextc = bp->text;
  485.         text->nleft = BLOCKSIZE - 1;
  486.     }
  487.     *text->nextc++ = c;
  488. }
  489.  
  490. /*
  491.  * Write the contents of a text structure to a file.
  492.  */
  493. void
  494. writetext(text, fp)
  495.     struct text *text;
  496.     FILE *fp;
  497.     {
  498.     struct block *bp;
  499.  
  500.     if (text->start != NULL) {
  501.         for (bp = text->start ; bp != text->last ; bp = bp->next)
  502.             fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
  503.         fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
  504.     }
  505. }
  506.  
  507. FILE *
  508. ckfopen(file, mode)
  509.     char *file;
  510.     char *mode;
  511.     {
  512.     FILE *fp;
  513.  
  514.     if ((fp = fopen(file, mode)) == NULL) {
  515.         fprintf(stderr, "Can't open %s\n", file);
  516.         exit(2);
  517.     }
  518.     return fp;
  519. }
  520.  
  521. void *
  522. ckmalloc(nbytes) {
  523.     register char *p;
  524.     char *malloc();
  525.  
  526.     if ((p = malloc(nbytes)) == NULL)
  527.         error("Out of space");
  528.     return p;
  529. }
  530.  
  531. char *
  532. savestr(s)
  533.     char *s;
  534.     {
  535.     register char *p;
  536.  
  537.     p = ckmalloc(strlen(s) + 1);
  538.     strcpy(p, s);
  539.     return p;
  540. }
  541.  
  542. void
  543. error(msg)
  544.     char *msg;
  545.     {
  546.     if (curfile != NULL)
  547.         fprintf(stderr, "%s:%d: ", curfile, linno);
  548.     fprintf(stderr, "%s\n", msg);
  549.     exit(2);
  550. }
  551.